﻿namespace Simulacion.Desktop.ViewModels
{
    using System.Collections.ObjectModel;
    using System.Diagnostics;

    using AlohaAlgorithm;

    using Distributions;

    using Microsoft.Practices.Composite.Presentation.Commands;

    using Network;

    using Shared;
    using CSMAAlgorithm;

    public class MainWindowViewModel : BaseModel
    {
        private readonly IMainWindow view;

        private bool isSimulationRunning;

        private int simulationProgress;

        private Network network;

        private double effectiveBandwith;

        public MainWindowViewModel(IMainWindow view)
        {
            this.view = view;
            this.StartSimulationCommand = new DelegateCommand<object>(this.StartSimulation, this.CanStartSimulation);
            this.Algorithms = new ObservableCollection<IAlgorithm>();

            IAlgorithm alohaAlgorithm = new AlohaAlgorithm(new RandomDistribution());
            IAlgorithm slottedAlohaAlgorithm = new SlottedAlohaAlgorithm(new RandomDistribution());
            IAlgorithm csmaPersitentAlgorithm = new CSMAPersistent(new RandomDistribution());


            this.Algorithms.Add(alohaAlgorithm);
            this.Algorithms.Add(slottedAlohaAlgorithm);
            this.Algorithms.Add(csmaPersitentAlgorithm);

            // TODO: Remove this before ship
            this.SelectedAlgorithm = this.Algorithms[0];
            this.KilobytesToTransmit = 1000;
            this.NetworkSpeed = 100;
        }

        public DelegateCommand<object> StartSimulationCommand { get; private set; }

        public ObservableCollection<IAlgorithm> Algorithms { get; private set; }

        public IAlgorithm SelectedAlgorithm { get; set; }

        public double KilobytesToTransmit { get; set; }

        public int NumberOfClients { get; set; }

        public double NetworkSpeed { get; set; }

        public Network Network
        {
            get
            {
                return this.network;
            }

            private set
            {
                this.network = value;
                this.OnPropertyChanged("Network");
            }
        }

        public double EffectiveBandwith
        {
            get
            {
                return this.effectiveBandwith;
            }

            private set
            {
                this.effectiveBandwith = value;
                this.OnPropertyChanged("EffectiveBandwith");
            }
        }

        public int SimulationProgress
        {
            get
            {
                return this.simulationProgress;
            }

            set
            {
                this.simulationProgress = value;
                this.OnPropertyChanged("SimulationProgress");
            }
        }

        private bool IsSimulationRunning
        {
            get
            {
                return this.isSimulationRunning;
            }

            set
            {
                this.isSimulationRunning = value;
                this.StartSimulationCommand.RaiseCanExecuteChanged();
            }
        }

        private void StartSimulation(object obj)
        {
            this.SimulationProgress = 0;
            this.EffectiveBandwith = 0;
            this.IsSimulationRunning = true;
            this.view.ClearGraphs();

            this.Network = new Network(this.SelectedAlgorithm, this.KilobytesToTransmit, this.NumberOfClients, this.NetworkSpeed);

            this.Network.Start(
                () =>
                {
                    this.EffectiveBandwith = (this.Network.Bandwith / this.NetworkSpeed) * 100;
                    
                    // this.EffectiveBandwith = (this.network.SuccesfulTransmissions > 0) ? this.EffectiveBandwith / this.network.SuccesfulTransmissions : 0;
                    this.IsSimulationRunning = false;
                    this.StartSimulationCommand.RaiseCanExecuteChanged();
                },
                progress =>
                    {
                        double timeBandwith = (progress.Bandwith / this.NetworkSpeed) * 100;
                        this.EffectiveBandwith = timeBandwith;
                        this.SimulationProgress = progress.Progress;
                        this.view.DrawPoint(progress.ElapsedTime, timeBandwith);
                    });
        }

        private bool CanStartSimulation(object arg)
        {
            return !this.IsSimulationRunning;
        }
    }
}
